package org.springframework.cloud.openfeign;

import static feign.Util.checkNotNull;

import com.opages.mvc.adapter.common.client.ServiceInstance;
import com.opages.mvc.adapter.common.client.discovery.DiscoveryClient;
import com.opages.mvc.adapter.common.constant.AdapterConstant;
import org.springframework.util.StringUtils;

import feign.Request;
import feign.RequestTemplate;
import feign.Target;

import java.util.Map;

public class FeignLoadBalancerTarget<T> implements Target<T>{

	private Class<T> type;
    private String name;
    private String url;
    private String path;
    private DiscoveryClient discovery;

    public FeignLoadBalancerTarget(Class<T> type, String name, String url, DiscoveryClient discovery) {
    	this.type = checkNotNull(type, "type");
    	this.name = name;
    	this.url = url;
    	if(StringUtils.isEmpty(name) && StringUtils.isEmpty(url)) {
    		throw new RuntimeException("name 或  url不能同时为空!");
    	}
    	this.discovery = checkNotNull(discovery,"discovery不允许为空！");
    }
    public FeignLoadBalancerTarget(Class<T> type, String name, String url,String path,DiscoveryClient discovery) {
        this.path = path;
        this.type = checkNotNull(type, "type");
        this.name = name;
        this.url = url;
        if(StringUtils.isEmpty(name) && StringUtils.isEmpty(url)) {
            throw new RuntimeException("name 或  url不能同时为空!");
        }
        this.discovery = checkNotNull(discovery,"discovery不允许为空！");
    }

    @Override
    public Class<T> type() {
      return type;
    }

    @Override
    public String name() {
      return name;
    }

    @Override
    public String url() {
    	if(!StringUtils.isEmpty(url)) {
    		return url;
    	}
        ServiceInstance serviceInstance = discovery.chooseServer(name);
        String serverPath = "";
        if(serviceInstance.getHost().indexOf("http") == -1) {
            serverPath = serviceInstance.getScheme()+"://";
        }
        serverPath += serviceInstance.getHost()+":"+serviceInstance.getPort();
        Map<String, String> metadata = serviceInstance.getMetadata();
        String contextPath = metadata.get(AdapterConstant.APPLICATION_CONTEXT_PATH);
        //拼接项目contextPath路径
        if(!StringUtils.isEmpty(contextPath)) {
            if(!contextPath.startsWith("/")) {
                contextPath += "/";
            }
            //存在path则以path为主
            if(!StringUtils.isEmpty(this.path)) {
                serverPath = serverPath + this.path;
            }else {
                serverPath = serverPath + contextPath;
            }

        }
    	return serverPath;
    }

    /* no authentication or other special activity. just insert the url. */
    @Override
    public Request apply(RequestTemplate input) {
      if (input.url().indexOf("http") != 0) {
        input.target(url());
      }
      return input.request();
    }

    @Override
    public boolean equals(Object obj) {
      if (obj instanceof HardCodedTarget) {
    	  FeignLoadBalancerTarget<?> other = (FeignLoadBalancerTarget) obj;
        return type.equals(other.type)
            && name.equals(other.name)
            && url.equals(other.url);
      }
      return false;
    }

    @Override
    public int hashCode() {
      int result = 17;
      result = 31 * result + type.hashCode();
      result = 31 * result + name.hashCode();
      result = 31 * result + url.hashCode();
      return result;
    }

    @Override
    public String toString() {
      if (name.equals(url)) {
        return "HardCodedTarget(type=" + type.getSimpleName() + ", url=" + url + ")";
      }
      return "HardCodedTarget(type=" + type.getSimpleName() + ", name=" + name + ", url=" + url
          + ")";
    }
}
